package xyz.zyt123.videowall.component;

import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import lombok.Setter;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.JavaFXFrameConverter;
import org.bytedeco.librealsense.frame;
import xyz.zyt123.videowall.bean.ErrorMsg;
import xyz.zyt123.videowall.dao.Dao;
import xyz.zyt123.videowall.util.CheckUtil;
import xyz.zyt123.videowall.util.ConfigUtil;

import javax.imageio.ImageIO;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;


public class VideoView extends AnchorPane {

    private final StringProperty title;
    private final IntegerProperty count = new SimpleIntegerProperty(0);
    private final StringProperty status = new SimpleStringProperty("正常");
    @Setter
    private String url;
    private ImageView imageView;
    private Timer timer;
    private long lastErrorTime = 0L;
    private FFmpegFrameGrabber fFmpegFrameGrabber;

    public VideoView(String title) {
        this.title = new SimpleStringProperty(title);
        draw();
    }

    public void draw() {
        Label title = new Label();
        title.textProperty().bind(Bindings.concat(this.title, ":", status));
        setTopAnchor(title, 10.0);
        setLeftAnchor(title, 10.0);

        Label errorCount = new Label();
        errorCount.textProperty().bind(Bindings.concat("异常次数: ", count));
        setRightAnchor(errorCount, 10.0);
        setTopAnchor(errorCount, 10.0);

        Pane pane = new Pane();
        pane.setStyle("-fx-border-color: rgba(0,0,255,100);-fx-border-width: 1px");
        setBottomAnchor(pane, 10.0);
        setTopAnchor(pane, 30.0);
        setLeftAnchor(pane, 10.0);
        setRightAnchor(pane, 10.0);
        imageView = new ImageView();
        imageView.setPreserveRatio(true);
        imageView.fitWidthProperty().bind(pane.widthProperty());
        imageView.fitHeightProperty().bind(pane.heightProperty());
        pane.getChildren().add(imageView);
        getChildren().addAll(title, errorCount, pane);
    }

    public void start() {
        if (url == null || url.isEmpty() || !new File(url).exists()) {
            status.set("文件不存在");
            return;
        }
        timer = new Timer(true);
        String imageFileAddress = ConfigUtil.getImageFileAddress();
        new File(imageFileAddress + "\\").mkdirs();
        try {
            avutil.av_log_set_level(avutil.AV_LOG_ERROR);
            fFmpegFrameGrabber = new FFmpegFrameGrabber(url);
            fFmpegFrameGrabber.start();
            int period = (int) (1000 / fFmpegFrameGrabber.getVideoFrameRate());
            int ftp = fFmpegFrameGrabber.getLengthInFrames();
            final int[] flag = {0};

            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    try {
                        flag[0]++;
                        Frame grab = fFmpegFrameGrabber.grabImage();
                        Image image = frameToBufferedImage(grab);
                        // 大于1s
                        if (CheckUtil.check(image)) {
                            if (lastErrorTime + 1000 < System.currentTimeMillis()) {
                                ErrorMsg errorMsg = new ErrorMsg(title.get(), "", (int) grab.timestamp / 1000000);
                                String filePath = imageFileAddress + "\\" + errorMsg.getUuid() +
                                        ".png";
                                errorMsg.setImagePath(filePath);
                                ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png",
                                        new FileOutputStream(filePath));
                                // 保存图片到硬盘，并且新增数据记录
                                lastErrorTime = System.currentTimeMillis();
                                Platform.runLater(() -> {
                                    count.set(count.get() + 1);
                                });
                                Dao.save(errorMsg);
                            }
                            Platform.runLater(() -> {
                                status.set("异常");
                            });
                        } else {
                            Platform.runLater(() -> {
                                status.set("正常");
                            });
                        }
                        Platform.runLater(() -> {
                            imageView.setImage(image);
                        });
                        // 视频播放完毕
                        if (ftp <= flag[0]) {
                            stop();
                        }
                    } catch (FrameGrabber.Exception e) {
                        Platform.runLater(() -> {
                            status.set("视频读取失败");
                        });
                    } catch (IOException ignored) {
                    }
                }
            }, 0, period);
        } catch (FrameGrabber.Exception e) {
            status.set("视频读取失败");
        }

    }

    /**
     * 帧转为流
     */
    public static Image frameToBufferedImage(Frame frame) {
        JavaFXFrameConverter javaFXFrameConverter = new JavaFXFrameConverter();
        //创建BufferedImage对象
        return javaFXFrameConverter.convert(frame);
    }

    public void stop() {
        if (fFmpegFrameGrabber != null) {
            try {
                fFmpegFrameGrabber.close();
                fFmpegFrameGrabber.release();
                fFmpegFrameGrabber = null;
            } catch (FrameGrabber.Exception e) {
            }
        }
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        Platform.runLater(() -> {
            status.set("未开始");
        });
    }

}
